from django.shortcuts import render
from django.views import View
from django.http import JsonResponse
import json
from django_redis import get_redis_connection
import base64, pickle
from apps.goods.models import SKU


# Create your views here.

class CartsView(View):

    def post(self, request):
        """
            保存购物车数据
        :param request:
        :return:
        """

        # 1、获取前端数据，json类型
        data_json = request.body.decode()
        # 2、将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = data_dict.get('sku_id')
        count = data_dict.get('count')
        selected = data_dict.get('selected', True)  # 前端未传递selected，可赋值True 。字典get方法获取数据不存在，给一个默认值
        # 4、验证数据
        # 4-1、验证数据完整性
        if not all([sku_id, count, selected]):
            return JsonResponse({'code': 400, 'errmsg': '数据不完整'}, status=400)
        # 4-2、验证商品是否存在
        try:
            SKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6、用户已登录，将数据保存在redis中
            # 6-1、建立redis连接
            conn = get_redis_connection('carts')
            # 6-2、将商品id和数量写入hash
            conn.hincrby('sku_count_%d' % user.id, sku_id, int(count))
            # 6-3、判断selected的状态是否为True，如果为True将商品id写入set中
            if selected:
                conn.sadd('selected_%d' % user.id, sku_id)

            return JsonResponse({
                'code': 0,
                'errmsg': 'ok'
            })

        else:
            response = JsonResponse({
                'code': 0,
                'errmsg': 'ok'
            })
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 7-3 未存储，则赋值一个空字典进行存储数据
                cart_dict = {}
            # 7-4、判断当前的sku_id是否已经在字典中，存在，说明商品已经添加过一次，需要对数量进行累加.。sku_id是字典key值
            if sku_id in cart_dict:
                count += int(cart_dict[sku_id]['count'])
            # 7-5、将新数据保存在字典中
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 7-6、对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response

    def get(self, request):
        """
            获取购物车数据
        :param request:
        :return:
        """
        # 1、判断用户是否登录，不同登录状态用户获取不同数据
        user = request.user
        if user.is_authenticated:
            # 2、登录用户，从reids中获取数据
            # 2-1、连接redis
            conn = get_redis_connection('carts')
            # 2-2、获取hash数据  {sku_id:count}
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            # 2-3、获取set数据 {sku_id1,ski_id2}
            selected_sku = conn.smembers('selected_%d' % user.id)
            # 2-4、将两部分数据构造成和cookie一样的字典嵌套形式，方便在第4步共同商品数据获取的方法  sku_count获取后是一个字典,里面的数据为bytes类型需要int强制类型转换
            cart_dict = {}
            for sku_id, count in sku_count.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in selected_sku  # sku_id在集合中返回True，不在返回False
                }

        else:
            # 3、未登录，从cookie中获取数据
            # 3-1、获取cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            # 3-2、判断cookie数据是否存在，在写入cookie时指定过有效期，超过有效期cookie不存在
            if cart_cookie is None:
                return JsonResponse({'code': 400, 'errmsg': '数据不存在'}, status=400)
            # 3-3、存在，对cookie数据进行解码
            cart_dict = pickle.loads(base64.b64decode(cart_cookie))
        # 4、根据获取到的sku_id查询sku表获取商品信息
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        # 5、构造返回的商品数据
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'count': cart_dict[sku.id]['count'],
                'selected': cart_dict[sku.id]['selected']
            })

        # 6、返回结果
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'cart_skus': cart_skus
        })

    def put(self, request):
        """
            修改购物车数据
        :param request:
        :return:
        """

        # 1、获取前端数据，json类型
        data_json = request.body.decode()
        # 2、将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = data_dict.get('sku_id')
        count = data_dict.get('count')
        selected = data_dict.get('selected', True)  # 前端未传递selected，可赋值True 。字典get方法获取数据不存在，给一个默认值
        # 4、验证数据
        # 4-1、验证数据完整性
        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '数据不完整'}, status=400)
        # 4-2、验证商品是否存在
        try:
            SKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6、用户已登录，将数据保存在redis中
            # 6-1、建立redis连接
            conn = get_redis_connection('carts')
            # 6-2、修改商品id和数量
            conn.hset('sku_count_%d' % user.id, sku_id, int(count))
            # 6-3、修改set中选中状态的sku_id
            if selected:
                # selected 为True 添加
                conn.sadd('selected_%d' % user.id, sku_id)
            else:
                # selected 为False 删除
                conn.srem('selected_%d' % user.id, sku_id)

            # 将修改后的数据返回
            cart_sku = {
                'count': count,
                'selected': selected
            }

            return JsonResponse({
                'code': 0,
                'errmsg': 'ok',
                'cart_sku': cart_sku
            })

        else:
            cart_sku = {
                'count': count,
                'selected': selected
            }
            response = JsonResponse({
                'code': 0,
                'errmsg': 'ok',
                'cart_sku': cart_sku
            })
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 7-3 未存储，则赋值一个空字典进行存储数据
                cart_dict = {}
            # 7-5、将新数据更新到字典中
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 7-6、对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response

    def delete(self, request):
        """
            删除购物车数据
        :param request:
        :return:
        """

        # 1、获取前端数据，json类型
        data_json = request.body.decode()
        # 2、将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3、提取字段 商品数量，商品id，选中状态
        sku_id = data_dict.get('sku_id')
        # 4、验证数据
        # 4-2、验证商品是否存在
        try:
            SKU.objects.get(id=sku_id)  # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'}, status=400)
        # 5、保存购物车数据之前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6、用户已登录，将数据保存在redis中
            # 6-1、建立redis连接
            conn = get_redis_connection('carts')
            # 6-2、将商品id和数量从hash删除 hdel
            conn.hdel('sku_count_%d' % user.id, sku_id)
            # 6-3、删除set数据 srem
            conn.srem('selected_%d' % user.id, sku_id)

            return JsonResponse({
                'code': 0,
                'errmsg': 'ok'
            })

        else:
            response = JsonResponse({
                'code': 0,
                'errmsg': 'ok'
            })
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                return response
            # 解码后的字典可能是空字典
            if cart_dict:
                # 7-5、删除字典中数据
                del cart_dict[sku_id]
            # 7-6、对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response


class CartsSelectionView(View):
    """
         购物车全选修改
    """

    def put(self, request):
        """
            修改购物车全选状态
        :param request:
        :return:
        """

        # 1、获取前端数据，json类型
        data_json = request.body.decode()
        # 2、将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3、提取字段 选中状态
        selected = data_dict.get('selected', True)  # 前端未传递selected，可赋值True 。字典get方法获取数据不存在，给一个默认值
        # 4、验证数据
        if selected:
            if not isinstance(selected, bool):
                return JsonResponse({'code': 400}, status=400)
                # 5、先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6、用户已登录，将数据保存在redis中
            # 6-1、建立redis连接
            conn = get_redis_connection('carts')
            # 6-2 获取全部的商品的sku_id，从hash中获取全部商品
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            sku_ids = sku_count.keys()
            # 6-3、修改全部商品的选中状态
            if selected:
                # selected 为True 添加
                conn.sadd('selected_%d' % user.id, *sku_ids)
            else:
                # selected 为False 删除
                conn.srem('selected_%d' % user.id, *sku_ids)

            # 将修改后的数据返回
            cart_sku = {
                'selected': selected
            }

            return JsonResponse({
                'code': 0,
                'errmsg': 'ok',
                'cart_sku': cart_sku
            })

        else:
            cart_sku = {
                'selected': selected
            }
            response = JsonResponse({
                'code': 0,
                'errmsg': 'ok',
                'cart_sku': cart_sku
            })
            # 7、用户未登录，将数据保存在cookie中
            # 7-1、先获取去一下cookie，判断一下是否已将存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 7-2、存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                return response
            # 7-5、将字典中所有的数据更新
            for sku_id,count_selecte in cart_dict.items():
                count_selecte['selected'] = selected

            # 7-6、对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 7-7、将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)
            # 8、返回结果
            return response

class CartsSimpleView(View):
    def get(self, request):
        """
            获取购物车数据
        :param request:
        :return:
        """
        # 1、判断用户是否登录，不同登录状态用户获取不同数据
        user = request.user
        if user.is_authenticated:
            # 2、登录用户，从reids中获取数据
            # 2-1、连接redis
            conn = get_redis_connection('carts')
            # 2-2、获取hash数据  {sku_id:count}
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            # 2-3、获取set数据 {sku_id1,ski_id2}
            selected_sku = conn.smembers('selected_%d' % user.id)
            # 2-4、将两部分数据构造成和cookie一样的字典嵌套形式，方便在第4步共同商品数据获取的方法  sku_count获取后是一个字典,里面的数据为bytes类型需要int强制类型转换
            cart_dict = {}
            for sku_id, count in sku_count.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in selected_sku  # sku_id在集合中返回True，不在返回False
                }

        else:
            # 3、未登录，从cookie中获取数据
            # 3-1、获取cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            # 3-2、判断cookie数据是否存在，在写入cookie时指定过有效期，超过有效期cookie不存在
            if cart_cookie is None:
                return JsonResponse({'code': 400, 'errmsg': '数据不存在'}, status=400)
            # 3-3、存在，对cookie数据进行解码
            cart_dict = pickle.loads(base64.b64decode(cart_cookie))
        # 4、根据获取到的sku_id查询sku表获取商品信息
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        # 5、构造返回的商品数据
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': cart_dict[sku.id]['count'],
            })

        # 6、返回结果
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'cart_skus': cart_skus
        })


